package com.icode.chat;

import com.alibaba.fastjson.JSON;
import com.icode.chat.message.ChatMessage;
import com.icode.chat.message.Message;
import com.icode.chat.message.ParticipateMessage;
import com.icode.chat.message.SystemMessage;
import com.icode.chat.message.decorator.DecoratedChatMessage;
import com.icode.chat.message.decorator.DecoratedSystemMessage;

import javax.websocket.RemoteEndpoint;
import javax.websocket.Session;
import java.io.IOException;
import java.util.*;

/**
 * Created with IntelliJ IDEA.
 * User: ZhongGang
 * Date: 14-8-2
 * Time: 上午1:15
 */
public class ChatRoom extends HashMap<Integer, Chat> {
    private static final Integer MAX_LATEST_MESSAGES = 20;

    private List<MessagePusher> messagePushers = new ArrayList<>();
    private Queue<Message> latestMessages = new ArrayDeque<>(MAX_LATEST_MESSAGES);

    public ChatRoom() {
        messagePushers.add(new SystemMessagePusher());
        messagePushers.add(new ChatMessagePusher());
        messagePushers.add(new ParticipateMessagePusher());
    }

    public void push(Message message) throws IOException {
        addLatestMessage(message);

        Collection<Chat> values = values();
        for (Chat chat : values) {
            Session session = chat.getSession();
            push(session, message);
        }
    }

    public void push(Session session, Message message) throws IOException {
        for (MessagePusher messagePusher : messagePushers) {
            if (messagePusher.support(message)) {
                messagePusher.send(session, message);
            }
        }
    }

    private void addLatestMessage(Message message) {
        latestMessages.add(message);
        if (latestMessages.size() > MAX_LATEST_MESSAGES) {
            latestMessages.poll();
        }
    }

    public void pushOnlineUsers() throws IOException {
        List<ParticipateMessage> messages = new ArrayList<>();
        Collection<Chat> values = values();
        for (Chat chat : values) {
            Session session = chat.getSession();
            messages.add(new ParticipateMessage(session.hashCode(), chat.getName(), true));
        }

        for (Chat chat : values) {
            Session session = chat.getSession();
            push(session, messages);
        }
    }

    private void push(Session session, List<ParticipateMessage> participateMessages) throws IOException {
        RemoteEndpoint.Basic basicRemote = session.getBasicRemote();
        String jsonMessage = JSON.toJSONString(participateMessages);
        basicRemote.sendText(jsonMessage);
    }

    interface MessagePusher {

        boolean support(Message message);

        void send(Session session, Message message) throws IOException;

    }

    class SystemMessagePusher implements MessagePusher {

        @Override
        public boolean support(Message message) {
            return message.getMessageType() == Message.MessageType.SYSTEM;
        }

        @Override
        public void send(Session session, Message message) throws IOException {
            SystemMessage systemMessage = (SystemMessage) message;
            RemoteEndpoint.Basic basicRemote = session.getBasicRemote();
            DecoratedSystemMessage decoratedMessage = new DecoratedSystemMessage(systemMessage);
            String jsonMessage = JSON.toJSONString(decoratedMessage);
            basicRemote.sendText(jsonMessage);
        }
    }

    class ChatMessagePusher implements MessagePusher {

        @Override
        public boolean support(Message message) {
            return message.getMessageType() == Message.MessageType.CHAT;
        }

        @Override
        public void send(Session session, Message message) throws IOException {
            ChatMessage chatMessage = (ChatMessage) message;
            RemoteEndpoint.Basic basicRemote = session.getBasicRemote();
            DecoratedChatMessage decoratedMessage = new DecoratedChatMessage(chatMessage);
            String jsonMessage = JSON.toJSONString(decoratedMessage);
            basicRemote.sendText(jsonMessage);
        }
    }

    class ParticipateMessagePusher implements MessagePusher {

        @Override
        public boolean support(Message message) {
            return message.getMessageType() == Message.MessageType.PARTICIPATE;
        }

        @Override
        public void send(Session session, Message message) throws IOException {
            ParticipateMessage participateMessage = (ParticipateMessage) message;
            RemoteEndpoint.Basic basicRemote = session.getBasicRemote();
            String jsonMessage = JSON.toJSONString(participateMessage);
            basicRemote.sendText(jsonMessage);
        }
    }

    public Queue<Message> getLatestMessages() {
        return latestMessages;
    }
}
